#include <iostream>
#include <functional>
#include <string>
#include <unistd.h>

#include "Log.hpp"
#include "Calculate.hpp"
#include "InetAddr.hpp"
#include "Socket.hpp"
#include "TcpServer.hpp"

using namespace socket_ns;

void Usage(std::string proc)
{
	std::cout << "Usage:\n\t" << proc << " local_port\n"
			  << std::endl;
}

using CalTask_t = std::function<Response(const Request &req)>;

class Service
{
public:
	Service(CalTask_t func) : _func(func)
	{
	}
	void SerServiceHelper(socket_sptr sockptr, InetAddr client)
	{
		int sockfd = sockptr->SockFd();
		LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.ip().c_str(), client.port(), sockfd);
		std::string clientaddr = "[" + client.ip() + ":" + std::to_string(client.port()) + "] ";

		std::string inbuffer;

		while (true)
		{

			sleep(1);
			// 1.接收报文
			Request req;
			ssize_t n = sockptr->Recv(&inbuffer);
			if (n < 0)
			{
				LOG(DEBUG, "client %s quit\n", clientaddr.c_str());
				break;
			}

			// 2.分析数据，确认读到一个完整报文
			std::string package;
			while (true)
			{
				sleep(1);
				std::cout << "inbuffer:" << inbuffer << std::endl;
				package = Decode(inbuffer);
				if(package.empty()) break;	//因为在Decode中，如果不是完整报文会返回空串
				std::cout << "------------------------begin---------------" << std::endl;
                std::cout << "req string:\n"
                          << package << std::endl;
				
				//3.反序列化
				req.DeSerialize(package);

				//4.业务处理
				Response resp = _func(req);
				
				//5.对应答结果作序列化
				std::string send_str;
				resp.Serialize(&send_str);

				std::cout << "resp Serialize:" << std::endl;
                std::cout << send_str << std::endl;

				//6.添加报头长度
				send_str = Encode(send_str);
				std::cout << "resp Encode:" << std::endl;
                std::cout << send_str << std::endl;

				sockptr->Send(send_str); // 本次不对发送做处理， EPOLL

				std::cout << "------------------------end---------------" << std::endl;
			}
		}
	}

private:
	CalTask_t _func;
};

// ./tcpserver port
int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		Usage(argv[0]);
		return 1;
	}

	/*
	daemon的底层实现是if(fork>0) exit; setsid();
	要把服务放到后台运行（守护进程），为什么要创建子进程呢？
	因为其实后台进程是创建了一个单独的会话运行，而且会有组pid，但是会话里的第一个进程一定不能是组长，这是规定
	所以通过子进程去处理，退出父进程，子进程就变成了一个孤儿进程，而孤儿进程一定不会是组长
	*/
	// 0: 要更改工作目录
    // 0: 输入输出要进行重定向
	daemon(1, 0);	// fork father exit
	// EnableScreen();
	EnableFile();
	uint16_t port = std::stoi(argv[1]);
	Calculate cal;
	Service CalService(std::bind(&Calculate::Excute,&cal,std::placeholders::_1));
	service_t service = std::bind(&Service::SerServiceHelper,&CalService,std::placeholders::_1,std::placeholders::_2);
	std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);
	tsvr->Loop();
    return 0;
}